home *** CD-ROM | disk | FTP | other *** search
/ Speccy ClassiX 1998 / Speccy ClassiX 98.iso / amiga_system / the_aminet / dev / gcc / ixemulsrc.lha / ixemul-41.4 / stdio_2 / vfscanf.c < prev    next >
C/C++ Source or Header  |  1995-05-17  |  18KB  |  759 lines

  1. /*-
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Chris Torek.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #if defined(LIBC_SCCS) && !defined(lint)
  38. static char sccsid[] = "@(#)vfscanf.c    5.6 (Berkeley) 2/24/91";
  39. #endif /* LIBC_SCCS and not lint */
  40.  
  41. #define KERNEL
  42. #include "ixemul.h"
  43.  
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <ctype.h>
  47. #if __STDC__
  48. #include <stdarg.h>
  49. #else
  50. #include <varargs.h>
  51. #endif
  52. #include "local.h"
  53.  
  54. #define FLOATING_POINT
  55.  
  56. #ifdef FLOATING_POINT
  57. #include "floatio.h"
  58. #define    BUF    (MAXEXP+MAXFRACT+3)    /* 3 = sign + decimal point + NUL */
  59. #else
  60. #define    BUF    40
  61. #endif
  62.  
  63. /*
  64.  * Flags used during conversion.
  65.  */
  66. #define    LONG        0x01    /* l: long or double */
  67. #define    LONGDBL        0x02    /* L: long double; unimplemented */
  68. #define    SHORT        0x04    /* h: short */
  69. #define    SUPPRESS    0x08    /* suppress assignment */
  70. #define    POINTER        0x10    /* weird %p pointer (`fake hex') */
  71. #define    NOSKIP        0x20    /* do not skip blanks */
  72.  
  73. /*
  74.  * The following are used in numeric conversions only:
  75.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  76.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  77.  */
  78. #define    SIGNOK        0x40    /* +/- is (still) legal */
  79. #define    NDIGITS        0x80    /* no digits detected */
  80.  
  81. #define    DPTOK        0x100    /* (float) decimal point is still legal */
  82. #define    EXPOK        0x200    /* (float) exponent (e+3, etc) still legal */
  83.  
  84. #define    PFXOK        0x100    /* 0x prefix is (still) legal */
  85. #define    NZDIGITS    0x200    /* no zero digits detected */
  86.  
  87. /*
  88.  * Conversion types.
  89.  */
  90. #define    CT_CHAR        0    /* %c conversion */
  91. #define    CT_CCL        1    /* %[...] conversion */
  92. #define    CT_STRING    2    /* %s conversion */
  93. #define    CT_INT        3    /* integer, i.e., strtol or strtoul */
  94. #define    CT_FLOAT    4    /* floating, i.e., strtod */
  95.  
  96. #define u_char unsigned char
  97. #define u_long unsigned long
  98.  
  99. static u_char *__sccl();
  100.  
  101. /*
  102.  * vfscanf
  103.  */
  104. __svfscanf(fp, fmt0, ap)
  105.     register FILE *fp;
  106.     char const *fmt0;
  107.     _VA_LIST_ ap;
  108. {
  109.     register u_char *fmt = (u_char *)fmt0;
  110.     register int c;        /* character from format, or conversion */
  111.     register size_t width;    /* field width, or 0 */
  112.     register char *p;    /* points into all kinds of strings */
  113.     register int n;        /* handy integer */
  114.     register int flags;    /* flags as defined above */
  115.     register char *p0;    /* saves original value of p when necessary */
  116.     int nassigned;        /* number of fields assigned */
  117.     int nread;        /* number of characters consumed from fp */
  118.     int base;        /* base argument to strtol/strtoul */
  119.     u_long (*ccfn)();    /* conversion function (strtol/strtoul) */
  120.     char ccltab[256];    /* character class table for %[...] */
  121.     char buf[BUF];        /* buffer for numeric conversions */
  122.  
  123.     /* `basefix' is used to avoid `if' tests in the integer scanner */
  124.     static const short basefix[17] =
  125.         { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  126.  
  127.     if (!fp)
  128.       return 0;
  129.  
  130.     nassigned = 0;
  131.     nread = 0;
  132.     base = 0;        /* XXX just to keep gcc happy */
  133.     ccfn = NULL;        /* XXX just to keep gcc happy */
  134.     for (;;) {
  135.         c = *fmt++;
  136.         if (c == 0)
  137.             return (nassigned);
  138.         if (isspace(c)) {
  139.             for (;;) {
  140.                 if (fp->_r <= 0 && __srefill(fp))
  141.                     return (nassigned);
  142.                 if (!isspace(*fp->_p))
  143.                     break;
  144.                 nread++, fp->_r--, fp->_p++;
  145.             }
  146.             continue;
  147.         }
  148.         if (c != '%')
  149.             goto literal;
  150.         width = 0;
  151.         flags = 0;
  152.         /*
  153.          * switch on the format.  continue if done;
  154.          * break once format type is derived.
  155.          */
  156. again:        c = *fmt++;
  157.         switch (c) {
  158.         case '%':
  159. literal:
  160.             if (fp->_r <= 0 && __srefill(fp))
  161.                 goto input_failure;
  162.             if (*fp->_p != c)
  163.                 goto match_failure;
  164.             fp->_r--, fp->_p++;
  165.             nread++;
  166.             continue;
  167.  
  168.         case '*':
  169.             flags |= SUPPRESS;
  170.             goto again;
  171.         case 'l':
  172.             flags |= LONG;
  173.             goto again;
  174.         case 'L':
  175.             flags |= LONGDBL;
  176.             goto again;
  177.         case 'h':
  178.             flags |= SHORT;
  179.             goto again;
  180.  
  181.         case '0': case '1': case '2': case '3': case '4':
  182.         case '5': case '6': case '7': case '8': case '9':
  183.             width = width * 10 + c - '0';
  184.             goto again;
  185.  
  186.         /*
  187.          * Conversions.
  188.          * Those marked `compat' are for 4.[123]BSD compatibility.
  189.          *
  190.          * (According to ANSI, E and X formats are supposed
  191.          * to the same as e and x.  Sorry about that.)
  192.          */
  193.         case 'D':    /* compat */
  194.             flags |= LONG;
  195.             /* FALLTHROUGH */
  196.         case 'd':
  197.             c = CT_INT;
  198.             ccfn = (u_long (*)())strtol;
  199.             base = 10;
  200.             break;
  201.  
  202.         case 'i':
  203.             c = CT_INT;
  204.             ccfn = (u_long (*)())strtol;
  205.             base = 0;
  206.             break;
  207.  
  208.         case 'O':    /* compat */
  209.             flags |= LONG;
  210.             /* FALLTHROUGH */
  211.         case 'o':
  212.             c = CT_INT;
  213.             ccfn = strtoul;
  214.             base = 8;
  215.             break;
  216.  
  217.         case 'u':
  218.             c = CT_INT;
  219.             ccfn = strtoul;
  220.             base = 10;
  221.             break;
  222.  
  223.         case 'X':    /* compat   XXX */
  224.             flags |= LONG;
  225.             /* FALLTHROUGH */
  226.         case 'x':
  227.             flags |= PFXOK;    /* enable 0x prefixing */
  228.             c = CT_INT;
  229.             ccfn = strtoul;
  230.             base = 16;
  231.             break;
  232.  
  233. #ifdef FLOATING_POINT
  234.         case 'E':    /* compat   XXX */
  235.         case 'F':    /* compat */
  236.             flags |= LONG;
  237.             /* FALLTHROUGH */
  238.         case 'e': case 'f': case 'g':
  239.             c = CT_FLOAT;
  240.             break;
  241. #endif
  242.  
  243.         case 's':
  244.             c = CT_STRING;
  245.             break;
  246.  
  247.         case '[':
  248.             fmt = __sccl(ccltab, fmt);
  249.             flags |= NOSKIP;
  250.             c = CT_CCL;
  251.             break;
  252.  
  253.         case 'c':
  254.             flags |= NOSKIP;
  255.             c = CT_CHAR;
  256.             break;
  257.  
  258.         case 'p':    /* pointer format is like hex */
  259.             flags |= POINTER | PFXOK;
  260.             c = CT_INT;
  261.             ccfn = strtoul;
  262.             base = 16;
  263.             break;
  264.  
  265.         case 'n':
  266.             if (flags & SUPPRESS)    /* ??? */
  267.                 continue;
  268.             if (flags & SHORT)
  269.                 *va_arg(ap, short *) = nread;
  270.             else if (flags & LONG)
  271.                 *va_arg(ap, long *) = nread;
  272.             else
  273.                 *va_arg(ap, int *) = nread;
  274.             continue;
  275.  
  276.         /*
  277.          * Disgusting backwards compatibility hacks.    XXX
  278.          */
  279.         case '\0':    /* compat */
  280.             return (EOF);
  281.  
  282.         default:    /* compat */
  283.             if (isupper(c))
  284.                 flags |= LONG;
  285.             c = CT_INT;
  286.             ccfn = (u_long (*)())strtol;
  287.             base = 10;
  288.             break;
  289.         }
  290.  
  291.         /*
  292.          * We have a conversion that requires input.
  293.          */
  294.         if (fp->_r <= 0 && __srefill(fp))
  295.             goto input_failure;
  296.  
  297.         /*
  298.          * Consume leading white space, except for formats
  299.          * that suppress this.
  300.          */
  301.         if ((flags & NOSKIP) == 0) {
  302.             while (isspace(*fp->_p)) {
  303.                 nread++;
  304.                 if (--fp->_r > 0)
  305.                     fp->_p++;
  306.                 else if (__srefill(fp))
  307.                     goto input_failure;
  308.             }
  309.             /*
  310.              * Note that there is at least one character in
  311.              * the buffer, so conversions that do not set NOSKIP
  312.              * ca no longer result in an input failure.
  313.              */
  314.         }
  315.  
  316.         /*
  317.          * Do the conversion.
  318.          */
  319.         switch (c) {
  320.  
  321.         case CT_CHAR:
  322.             /* scan arbitrary characters (sets NOSKIP) */
  323.             if (width == 0)
  324.                 width = 1;
  325.             if (flags & SUPPRESS) {
  326.                 size_t sum = 0;
  327.                 for (;;) {
  328.                     if ((n = fp->_r) < width) {
  329.                         sum += n;
  330.                         width -= n;
  331.                         fp->_p += n;
  332.                         if (__srefill(fp)) {
  333.                             if (sum == 0)
  334.                                 goto input_failure;
  335.                             break;
  336.                         }
  337.                     } else {
  338.                         sum += width;
  339.                         fp->_r -= width;
  340.                         fp->_p += width;
  341.                         break;
  342.                     }
  343.                 }
  344.                 nread += sum;
  345.             } else {
  346.                 size_t r = fread((void *)va_arg(ap, char *), 1,
  347.                     width, fp);
  348.  
  349.                 if (r == 0)
  350.                     goto input_failure;
  351.                 nread += r;
  352.                 nassigned++;
  353.             }
  354.             break;
  355.  
  356.         case CT_CCL:
  357.             /* scan a (nonempty) character class (sets NOSKIP) */
  358.             if (width == 0)
  359.                 width = ~0;    /* `infinity' */
  360.             /* take only those things in the class */
  361.             if (flags & SUPPRESS) {
  362.                 n = 0;
  363.                 while (ccltab[*fp->_p]) {
  364.                     n++, fp->_r--, fp->_p++;
  365.                     if (--width == 0)
  366.                         break;
  367.                     if (fp->_r <= 0 && __srefill(fp)) {
  368.                         if (n == 0)
  369.                             goto input_failure;
  370.                         break;
  371.                     }
  372.                 }
  373.                 if (n == 0)
  374.                     goto match_failure;
  375.             } else {
  376.                 p0 = p = va_arg(ap, char *);
  377.                 while (ccltab[*fp->_p]) {
  378.                     fp->_r--;
  379.                     *p++ = *fp->_p++;
  380.                     if (--width == 0)
  381.                         break;
  382.                     if (fp->_r <= 0 && __srefill(fp)) {
  383.                         if (p == p0)
  384.                             goto input_failure;
  385.                         break;
  386.                     }
  387.                 }
  388.                 n = p - p0;
  389.                 if (n == 0)
  390.                     goto match_failure;
  391.                 *p = 0;
  392.                 nassigned++;
  393.             }
  394.             nread += n;
  395.             break;
  396.  
  397.         case CT_STRING:
  398.             /* like CCL, but zero-length string OK, & no NOSKIP */
  399.             if (width == 0)
  400.                 width = ~0;
  401.             if (flags & SUPPRESS) {
  402.                 n = 0;
  403.                 while (!isspace(*fp->_p)) {
  404.                     n++, fp->_r--, fp->_p++;
  405.                     if (--width == 0)
  406.                         break;
  407.                     if (fp->_r <= 0 && __srefill(fp))
  408.                         break;
  409.                 }
  410.                 nread += n;
  411.             } else {
  412.                 p0 = p = va_arg(ap, char *);
  413.                 while (!isspace(*fp->_p)) {
  414.                     fp->_r--;
  415.                     *p++ = *fp->_p++;
  416.                     if (--width == 0)
  417.                         break;
  418.                     if (fp->_r <= 0 && __srefill(fp))
  419.                         break;
  420.                 }
  421.                 *p = 0;
  422.                 nread += p - p0;
  423.                 nassigned++;
  424.             }
  425.             continue;
  426.  
  427.         case CT_INT:
  428.             /* scan an integer as if by strtol/strtoul */
  429. #ifdef hardway
  430.             if (width == 0 || width > sizeof(buf) - 1)
  431.                 width = sizeof(buf) - 1;
  432. #else
  433.             /* size_t is unsigned, hence this optimisation */
  434.             if (--width > sizeof(buf) - 2)
  435.                 width = sizeof(buf) - 2;
  436.             width++;
  437. #endif
  438.             flags |= SIGNOK | NDIGITS | NZDIGITS;
  439.             for (p = buf; width; width--) {
  440.                 c = *fp->_p;
  441.                 /*
  442.                  * Switch on the character; `goto ok'
  443.                  * if we accept it as a part of number.
  444.                  */
  445.                 switch (c) {
  446.  
  447.                 /*
  448.                  * The digit 0 is always legal, but is
  449.                  * special.  For %i conversions, if no
  450.                  * digits (zero or nonzero) have been
  451.                  * scanned (only signs), we will have
  452.                  * base==0.  In that case, we should set
  453.                  * it to 8 and enable 0x prefixing.
  454.                  * Also, if we have not scanned zero digits
  455.                  * before this, do not turn off prefixing
  456.                  * (someone else will turn it off if we
  457.                  * have scanned any nonzero digits).
  458.                  */
  459.                 case '0':
  460.                     if (base == 0) {
  461.                         base = 8;
  462.                         flags |= PFXOK;
  463.                     }
  464.                     if (flags & NZDIGITS)
  465.                         flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  466.                     else
  467.                         flags &= ~(SIGNOK|PFXOK|NDIGITS);
  468.                     goto ok;
  469.  
  470.                 /* 1 through 7 always legal */
  471.                 case '1': case '2': case '3':
  472.                 case '4': case '5': case '6': case '7':
  473.                     base = basefix[base];
  474.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  475.                     goto ok;
  476.  
  477.                 /* digits 8 and 9 ok iff decimal or hex */
  478.                 case '8': case '9':
  479.                     base = basefix[base];
  480.                     if (base <= 8)
  481.                         break;    /* not legal here */
  482.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  483.                     goto ok;
  484.  
  485.                 /* letters ok iff hex */
  486.                 case 'A': case 'B': case 'C':
  487.                 case 'D': case 'E': case 'F':
  488.                 case 'a': case 'b': case 'c':
  489.                 case 'd': case 'e': case 'f':
  490.                     /* no need to fix base here */
  491.                     if (base <= 10)
  492.                         break;    /* not legal here */
  493.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  494.                     goto ok;
  495.  
  496.                 /* sign ok only as first character */
  497.                 case '+': case '-':
  498.                     if (flags & SIGNOK) {
  499.                         flags &= ~SIGNOK;
  500.                         goto ok;
  501.                     }
  502.                     break;
  503.  
  504.                 /* x ok iff flag still set & 2nd char */
  505.                 case 'x': case 'X':
  506.                     if (flags & PFXOK && p == buf + 1) {
  507.                         base = 16;    /* if %i */
  508.                         flags &= ~PFXOK;
  509.                         goto ok;
  510.                     }
  511.                     break;
  512.                 }
  513.  
  514.                 /*
  515.                  * If we got here, c is not a legal character
  516.                  * for a number.  Stop accumulating digits.
  517.                  */
  518.                 break;
  519.         ok:
  520.                 /*
  521.                  * c is legal: store it and look at the next.
  522.                  */
  523.                 *p++ = c;
  524.                 if (--fp->_r > 0)
  525.                     fp->_p++;
  526.                 else if (__srefill(fp))
  527.                     break;        /* EOF */
  528.             }
  529.             /*
  530.              * If we had only a sign, it is no good; push
  531.              * back the sign.  If the number ends in `x',
  532.              * it was [sign] '0' 'x', so push back the x
  533.              * and treat it as [sign] '0'.
  534.              */
  535.             if (flags & NDIGITS) {
  536.                 if (p > buf)
  537.                     (void) ungetc(*(u_char *)--p, fp);
  538.                 goto match_failure;
  539.             }
  540.             c = ((u_char *)p)[-1];
  541.             if (c == 'x' || c == 'X') {
  542.                 --p;
  543.                 (void) ungetc(c, fp);
  544.             }
  545.             if ((flags & SUPPRESS) == 0) {
  546.                 u_long res;
  547.  
  548.                 *p = 0;
  549.                 res = (*ccfn)(buf, (char **)NULL, base);
  550.                 if (flags & POINTER)
  551.                     *va_arg(ap, void **) = (void *)res;
  552.                 else if (flags & SHORT)
  553.                     *va_arg(ap, short *) = res;
  554.                 else if (flags & LONG)
  555.                     *va_arg(ap, long *) = res;
  556.                 else
  557.                     *va_arg(ap, int *) = res;
  558.                 nassigned++;
  559.             }
  560.             nread += p - buf;
  561.             break;
  562.  
  563. #ifdef FLOATING_POINT
  564.         case CT_FLOAT:
  565.             /* scan a floating point number as if by strtod */
  566. #ifdef hardway
  567.             if (width == 0 || width > sizeof(buf) - 1)
  568.                 width = sizeof(buf) - 1;
  569. #else
  570.             /* size_t is unsigned, hence this optimisation */
  571.             if (--width > sizeof(buf) - 2)
  572.                 width = sizeof(buf) - 2;
  573.             width++;
  574. #endif
  575.             flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  576.             for (p = buf; width; width--) {
  577.                 c = *fp->_p;
  578.                 /*
  579.                  * This code mimicks the integer conversion
  580.                  * code, but is much simpler.
  581.                  */
  582.                 switch (c) {
  583.  
  584.                 case '0': case '1': case '2': case '3':
  585.                 case '4': case '5': case '6': case '7':
  586.                 case '8': case '9':
  587.                     flags &= ~(SIGNOK | NDIGITS);
  588.                     goto fok;
  589.  
  590.                 case '+': case '-':
  591.                     if (flags & SIGNOK) {
  592.                         flags &= ~SIGNOK;
  593.                         goto fok;
  594.                     }
  595.                     break;
  596.                 case '.':
  597.                     if (flags & DPTOK) {
  598.                         flags &= ~(SIGNOK | DPTOK);
  599.                         goto fok;
  600.                     }
  601.                     break;
  602.                 case 'e': case 'E':
  603.                     /* no exponent without some digits */
  604.                     if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  605.                         flags =
  606.                             (flags & ~(EXPOK|DPTOK)) |
  607.                             SIGNOK | NDIGITS;
  608.                         goto fok;
  609.                     }
  610.                     break;
  611.                 }
  612.                 break;
  613.         fok:
  614.                 *p++ = c;
  615.                 if (--fp->_r > 0)
  616.                     fp->_p++;
  617.                 else if (__srefill(fp))
  618.                     break;    /* EOF */
  619.             }
  620.             /*
  621.              * If no digits, might be missing exponent digits
  622.              * (just give back the exponent) or might be missing
  623.              * regular digits, but had sign and/or decimal point.
  624.              */
  625.             if (flags & NDIGITS) {
  626.                 if (flags & EXPOK) {
  627.                     /* no digits at all */
  628.                     while (p > buf)
  629.                         ungetc(*(u_char *)--p, fp);
  630.                     goto match_failure;
  631.                 }
  632.                 /* just a bad exponent (e and maybe sign) */
  633.                 c = *(u_char *)--p;
  634.                 if (c != 'e' && c != 'E') {
  635.                     (void) ungetc(c, fp);/* sign */
  636.                     c = *(u_char *)--p;
  637.                 }
  638.                 (void) ungetc(c, fp);
  639.             }
  640.             if ((flags & SUPPRESS) == 0) {
  641.                 double res;
  642.  
  643.                 *p = 0;
  644.                 res = atof(buf);
  645.                 if (flags & LONG)
  646.                     *va_arg(ap, double *) = res;
  647.                 else
  648.                     *va_arg(ap, float *) = res;
  649.                 nassigned++;
  650.             }
  651.             nread += p - buf;
  652.             break;
  653. #endif /* FLOATING_POINT */
  654.         }
  655.     }
  656. input_failure:
  657.     return (nassigned ? nassigned : -1);
  658. match_failure:
  659.     return (nassigned);
  660. }
  661.  
  662. /*
  663.  * Fill in the given table from the scanset at the given format
  664.  * (just after `[').  Return a pointer to the character past the
  665.  * closing `]'.  The table has a 1 wherever characters should be
  666.  * considered part of the scanset.
  667.  */
  668. static u_char *
  669. __sccl(tab, fmt)
  670.     register char *tab;
  671.     register u_char *fmt;
  672. {
  673.     register int c, n, v;
  674.  
  675.     /* first `clear' the whole table */
  676.     c = *fmt++;        /* first char hat => negated scanset */
  677.     if (c == '^') {
  678.         v = 1;        /* default => accept */
  679.         c = *fmt++;    /* get new first char */
  680.     } else
  681.         v = 0;        /* default => reject */
  682.     /* should probably use memset here */
  683.     for (n = 0; n < 256; n++)
  684.         tab[n] = v;
  685.     if (c == 0)
  686.         return (fmt - 1);/* format ended before closing ] */
  687.  
  688.     /*
  689.      * Now set the entries corresponding to the actual scanset
  690.      * to the opposite of the above.
  691.      *
  692.      * The first character may be ']' (or '-') without being special;
  693.      * the last character may be '-'.
  694.      */
  695.     v = 1 - v;
  696.     for (;;) {
  697.         tab[c] = v;        /* take character c */
  698. doswitch:
  699.         n = *fmt++;        /* and examine the next */
  700.         switch (n) {
  701.  
  702.         case 0:            /* format ended too soon */
  703.             return (fmt - 1);
  704.  
  705.         case '-':
  706.             /*
  707.              * A scanset of the form
  708.              *    [01+-]
  709.              * is defined as `the digit 0, the digit 1,
  710.              * the character +, the character -', but
  711.              * the effect of a scanset such as
  712.              *    [a-zA-Z0-9]
  713.              * is implementation defined.  The V7 Unix
  714.              * scanf treats `a-z' as `the letters a through
  715.              * z', but treats `a-a' as `the letter a, the
  716.              * character -, and the letter a'.
  717.              *
  718.              * For compatibility, the `-' is not considerd
  719.              * to define a range if the character following
  720.              * it is either a close bracket (required by ANSI)
  721.              * or is not numerically greater than the character
  722.              * we just stored in the table (c).
  723.              */
  724.             n = *fmt;
  725.             if (n == ']' || n < c) {
  726.                 c = '-';
  727.                 break;    /* resume the for(;;) */
  728.             }
  729.             fmt++;
  730.             do {        /* fill in the range */
  731.                 tab[++c] = v;
  732.             } while (c < n);
  733. #if 1    /* XXX another disgusting compatibility hack */
  734.             /*
  735.              * Alas, the V7 Unix scanf also treats formats
  736.              * such as [a-c-e] as `the letters a through e'.
  737.              * This too is permitted by the standard....
  738.              */
  739.             goto doswitch;
  740. #else
  741.             c = *fmt++;
  742.             if (c == 0)
  743.                 return (fmt - 1);
  744.             if (c == ']')
  745.                 return (fmt);
  746. #endif
  747.             break;
  748.  
  749.         case ']':        /* end of scanset */
  750.             return (fmt);
  751.  
  752.         default:        /* just another character */
  753.             c = n;
  754.             break;
  755.         }
  756.     }
  757.     /* NOTREACHED */
  758. }
  759.